from flask import Blueprint, request, jsonify, g
from project_model import UserBehavior, TokenRecord, User, Role
from tools import token_required, log_operations
from global_scope import get_db, get_bcrypt

db = get_db()
bcrypt = get_bcrypt()

user_bp = Blueprint("用户", __name__, url_prefix='/user')


@user_bp.route('/detail', methods=['GET'])
@log_operations
@token_required
def user_detail():
    user = db.session.get(User, g.user_id)
    if not user:
        return jsonify(
            {"code": 1, "message": "User not found", "originUrl": request.path}), 404

    profile = {
        "id": None,
        "nickName": None,
        "gender": None,
        "avatar": None,
        "address": None,
        "email": None,
        "userId": None
    }
    if user.profile and user.profile[0]:
        p = user.profile[0]
        profile = {
            "id": p.id,
            "nickName": p.nickName,
            "gender": p.gender,
            "avatar": p.avatar,
            "address": p.address,
            "email": p.email,
            "userId": user.id
        }

    user_data = {
        "id": user.id,
        "username": user.username,
        "enable": bool(user.enable),
        "createTime": user.createTime.isoformat(),
        "updateTime": user.updateTime.isoformat(),
        "profile": profile,
        "roles": [
            {
                "id": role.id,
                "code": role.code,
                "name": role.name,
                "enable": bool(role.enable)
            } for role in user.roles
        ]
    }

    current_role = dict()
    if user.roles:
        for role in user.roles:
            if role.id == g.current_role:
                current_role = {
                    "id": role.id,
                    "code": role.code,
                    "name": role.name,
                    "enable": bool(role.enable)
                }
                break
    user_data["currentRole"] = current_role
    return jsonify(
        {"code": 0, "message": "OK", "data": user_data, "originUrl": request.path}), 200


@user_bp.route('', methods=['GET'])
@log_operations
@token_required
def get_user_list():
    username = request.args.get('username', None)
    page_no = int(request.args.get('pageNo', 1))
    page_size = int(request.args.get('pageSize', 10))

    query = User.query
    if username:
        query = query.filter(User.username == username)

    total = query.count()
    users = query.offset((page_no - 1) * page_size).limit(page_size).all()

    user_list = []
    for user in users:
        user_data = {
            "id": user.id,
            "username": user.username,
            "enable": bool(user.enable),
            "createTime": user.createTime.isoformat(),
            "updateTime": user.updateTime.isoformat(),
            "roles": [
                {
                    "id": role.id,
                    "code": role.code,
                    "name": role.name,
                    "enable": bool(role.enable)
                } for role in user.roles
            ],
            "gender": user.profile[0].gender if user.profile else None,
            "avatar": user.profile[0].avatar if user.profile else None,
            "address": user.profile[0].address if user.profile else None,
            "email": user.profile[0].email if user.profile else None
        }
        user_list.append(user_data)

    response = {
        "code": 0,
        "message": "OK",
        "data": {
            "pageData": user_list,
            "total": total
        },
        "originUrl": request.path + '?' + request.query_string.decode()
    }

    return jsonify(response), 200


@user_bp.route('/<int:user_id>', methods=['DELETE'])
@log_operations
@token_required
def delete_user(user_id):
    user = db.session.get(User, user_id)
    if not user:
        return jsonify(
            {"code": 1, "message": "User not found", "originUrl": request.path}), 404

    db.session.delete(user)
    tokens = TokenRecord.query.filter(TokenRecord.user_id == user.id).all()
    if tokens:
        db.session.delete(*tokens)
    db.session.commit()
    response_data = {
        'code': 0,
        'message': 'OK',
        'data': {},
        'originUrl': f'/user/{user_id}'
    }

    return jsonify(response_data), 200


@user_bp.route('/<int:user_id>', methods=['PATCH'])
@log_operations
@token_required
def update_user(user_id):
    update_data = request.json

    user = db.session.get(User, user_id)
    if not user:
        return jsonify({"code": 1, "message": "User not found", "originUrl": request.path}), 404

    if 'username' in update_data:
        user.username = update_data['username']
    if 'password' in update_data:
        user.password = bcrypt.generate_password_hash(update_data['password']).decode("utf-8")
    if 'enable' in update_data:
        user.enable = update_data['enable']

    if 'roleIds' in update_data:
        user.roles = [db.session.get(Role, role_id) for role_id in update_data['roleIds']]

    db.session.commit()

    user_data = {
        "id": user.id,
        "username": user.username,
        "enable": bool(user.enable),
        "createTime": user.createTime.isoformat(),
        "updateTime": user.updateTime.isoformat(),
        "roles": [
            {
                "id": role.id,
                "code": role.code,
                "name": role.name,
                "enable": bool(role.enable)
            } for role in user.roles
        ],
        "gender": user.profile[0].gender if user.profile else None,
        "avatar": user.profile[0].avatar if user.profile else None,
        "address": user.profile[0].address if user.profile else None,
        "email": user.profile[0].email if user.profile else None
    }

    return jsonify({"code": 0, "message": "OK", "data": user_data, "originUrl": f'/user/{user_id}'}), 200


@user_bp.route('/password/reset/<int:user_id>', methods=['PATCH'])
@log_operations
@token_required
def reset_password(user_id):
    data = request.json

    new_password = data.get('password')
    if not new_password:
        return jsonify({"code": 1, "message": "New password is required", "originUrl": request.path}), 400

    user = db.session.get(User, user_id)
    if not user:
        return jsonify({"code": 1, "message": "User not found", "originUrl": request.path}), 404

    user.password = bcrypt.generate_password_hash(new_password).decode("utf-8")

    token_records = TokenRecord.query.filter(TokenRecord.user_id == user.id).all()
    if token_records:
        db.session.delete(*token_records)
    db.session.commit()

    response_data = {
        'code': 0,
        'message': 'OK',
        'data': {},
        'originUrl': f'/password/reset/{user_id}'
    }

    return jsonify(response_data), 200


@user_bp.route('', methods=['POST'])
@log_operations
@token_required
def add_user():
    user_data = request.json
    username = user_data.get('username')
    password = user_data.get('password')
    role_ids = user_data.get('roleIds', [])

    if not username or not password:
        return jsonify({"code": 1, "message": "Username, password and roleIds are required"}), 400

    if User.query.filter_by(username=username).first():
        return jsonify({"code": 1, "message": "User already exists"}), 409

    new_user = User(username=username, password=bcrypt.generate_password_hash(password).decode("utf-8"))

    for role_id in role_ids:
        role = db.session.get(Role, role_id)
        if role:
            new_user.roles.append(role)

    db.session.add(new_user)
    db.session.commit()

    response_data = {
        'code': 0,
        'message': 'OK',
        'data': {
            'id': new_user.id,
            'username': new_user.username,
            'enable': bool(new_user.enable),
            'createTime': new_user.createTime.isoformat(),
            'updateTime': new_user.updateTime.isoformat()
        },
        'originUrl': '/user'
    }

    return jsonify(response_data), 201


@user_bp.route('/behavior', methods=['GET'])
@log_operations
@token_required
def get_user_behavior_paginated():
    page = request.args.get('page', 1, type=int)
    per_page = request.args.get('per_page', 10, type=int)
    user_id = request.args.get('user_id', None, type=int)

    query = UserBehavior.query.filter(UserBehavior.user_id == user_id) if user_id else UserBehavior.query
    behavior = query.order_by(UserBehavior.behavior_time.desc()).paginate(page, per_page, error_out=False)

    return jsonify({
        'page': behavior.page,
        'per_page': behavior.per_page,
        'total': behavior.total,
        'behaviors': [{
            'id': behavior.id,
            'user_id': behavior.user_id,
            'behavior_time': behavior.behavior_time.strftime('%Y-%m-%d %H:%M:%S'),
            'detail': behavior.detail
        } for behavior in behavior.items]
    })
